/** \file    arr2d_wise_iterator.h
  * \brief   not only allows linear iteration through Arr2d but also provides information about current (x,y).
  * \date    2001
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/xtd/arr2d_wise_iterator.h,v 1.1 2004/12/10 05:10:45 cscom1r4 Exp $
  */

#ifndef _arr2d_wise_iterator_h_
#define _arr2d_wise_iterator_h_

#include "Arr2D.h"

namespace xtd {

template < class T >
class arr2d_wise_iterator
{
public:
	//default ctor
	arr2d_wise_iterator() {}
	//ctor by coordinate
	arr2d_wise_iterator( YATL::Arr2D<T> &a, int x, int y ) : _a(&a), _x(x), _y(y) {
		_ptr = &a(x,y);
	}
	//ctor of end interator
	arr2d_wise_iterator(YATL::Arr2D<T> &a, bool) : _a(&a) {
		_ptr = a.end();
	}
	T& operator *() {
		return *_ptr;
	}
	T* operator ->() {
		return _ptr;
	}
	operator T*() {
		return _ptr;
	}
	int x() const { return _x; }
	int y() const { return _y; }
	arr2d_wise_iterator& operator ++() {
		++_ptr;
		if( ++_x == _a->Width() ) {
			_x = 0;
			++_y;
		}
		return *this;
	}
	bool operator ==( const arr2d_wise_iterator<T> &x ) {
		return _ptr == x._ptr;
	}
	bool operator !=( const arr2d_wise_iterator<T> &x ) {
		return _ptr != x._ptr;
	}
	bool operator ==( const T* ptr ) {
		return _ptr == ptr;
	}
	bool operator !=( const T* ptr ) {
		return _ptr != ptr;
	}
	bool operator ==( T* ptr ) {
		return _ptr == ptr;
	}
	bool operator !=( T* ptr ) {
		return _ptr != ptr;
	}

	//neighbours access
	T& rel( int dx, int dy ) 
		{ return _a->At(_x+dx,_y+dy); }
	//quick access to four neighbours
	T& top() 
		{ assert( _y!=0 );
		  return *(_ptr-_a->Width()); }
	T& bottom() 
		{ assert( _y!=_a.Height()-1 );
		  return *(_ptr+_a->Width()); }
	T& left() 
		{ assert( _x!=0 );
		  return *(_ptr-1); }
	T& right() 
		{ assert( _x!=_a->Width()-1 );
		  return *(_ptr+1); }

private:
	YATL::Arr2D<T> *		_a;
	T*						_ptr;
	int						_x;
	int						_y;
	friend class arr2d_wise_const_iterator<T>;
};

template < class T >
class arr2d_wise_const_iterator
{
public:
	//default ctor
	arr2d_wise_const_iterator() {}
	//ctor by coordinate
	arr2d_wise_const_iterator( const YATL::Arr2D<T> &a, int x, int y ) : _a(&a), _x(x), _y(y) {
		_ptr = &a(x,y);
	}
	//from not-const iterator
	arr2d_wise_const_iterator(arr2d_wise_iterator<T> i) : 
		_a(i._a), _x(i._x), _y(i._y), _ptr(i._ptr) {}
	//ctor of end interator
	arr2d_wise_const_iterator(const YATL::Arr2D<T> &a, bool) : _a(&a) {
		_ptr = a.end();
	}
	const T& operator *() const {
		return *_ptr;
	}
	const T* operator ->() const {
		return _ptr;
	}
	operator const T*() {
		return _ptr;
	}
	int x() const { return _x; }
	int y() const { return _y; }
	arr2d_wise_const_iterator& operator ++() {
		++_ptr;
		if( ++_x == _a->Width() ) {
			_x = 0;
			++_y;
		}
		return *this;
	}
	bool operator ==( const arr2d_wise_const_iterator<T> &x ) {
		return _ptr == x._ptr;
	}
	bool operator !=( const arr2d_wise_const_iterator<T> &x ) {
		return _ptr != x._ptr;
	}
	bool operator ==( const T* ptr ) {
		return _ptr == ptr;
	}
	bool operator !=( const T* ptr ) {
		return _ptr != ptr;
	}

	//neighbours access
	const T& rel( int dx, int dy ) const
		{ return _a->At(_x+dx,_y+dy); }
	//quick access to four neighbours
	const T& top() const
		{ assert( _y!=0 );
		  return *(_ptr-_a->Width()); }
	const T& bottom() const
		{ assert( _y!=_a->Height()-1 );
		  return *(_ptr+_a->Width()); }
	const T& left() const
		{ assert( _x!=0 );
		  return *(_ptr-1); }
	const T& right() const
		{ assert( _x!=_a->Width()-1 );
		  return *(_ptr+1); }

private:
	const YATL::Arr2D<T> *	_a;
	const T*				_ptr;
	int						_x;
	int						_y;
};

} //namespace xtd

#endif //_arr2d_wise_iterator_h_
